//--------------------------------------------------------------------------------------------------
//                                                   ___  __  __  __  __  __  __  __    __  __  ___ 
// Copyright 2010, Koert van der Veer.              / __)(  )(  )(  \/  )(  )(  )(  )  (  )(  )/ __)
// Licensed under the Apache License,              ( (__  )(__)(  )    (  )(__)(  )(__  )(__)( \__ \
// version 2.0; ("the License")                     \___)(______)(_/\/\_)(______)(____)(______)(___/

// You may not use this file except in compliance with the License.
// You may obtain a copy of the License at 
//     http://www.apache.org/licenses/LICENSE-2.0 
//
// Unless required by applicable law or agreed to in writing, software distributed under the License
// is distributed on an "AS IS" BASIS,  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
// or implied. See the License for the specific language governing permissions and limitations under
// the License. 
//--------------------------------------------------------------------------------------------------
// This file is part of cumulus,  an memory manager implementation in C++.  Details are discussed in
// my blog,  which can be found at http://ondergetekende.nl.  Comments,  suggestions and bug reports
// are welcome. They can be added as comments at the blog. Be advised that in its current form, this
// code is most likely not production ready; it simply hasn't been tested sufficiently. 
//--------------------------------------------------------------------------------------------------
// A memory allocator which just wraps the win32 heaps.
// Two heaps are provided: 
// * Win32ProcessHeap, which wraps the (shared) process heap
// * Win32PrivateHeap, which creates a private heap with custom parameters
// ------------------------------------------------------------------------------------------------

#pragma once

#include <windows.h>

#include "Interface.h"

namespace Cumulus 
{

template< bool TopDown=true, bool EnableExecute=false >
class Win32VirtualAlloc : public Interface
{
public:
	// VirtualAlloc always returns page aligned pointers (4k)
	static const size_t MinAlignment = 4096;

	// VirtualAlloc always returns at least a page
	static const size_t MinSize = 4096;

public:
	void* Malloc( size_t& Size ) 
	{
		DWORD Flags = MEM_COMMIT | MEM_RESERVE;

		if( TopDown )
		{
			Flags |= MEM_TOP_DOWN;
		}

		DWORD Protection = EnableExecute ?
			PAGE_EXECUTE_READWRITE :
			PAGE_READWRITE;

		void* Result = VirtualAlloc( 
			NULL, 
			Size, 
			Flags,
			Protection );

		// Round size up to the next page size
		Size = ( Size + MinAlignment - 1 ) & ~( MinAlignment - 1 );

		// Update Size parameter. (optional)
		// Size = GetSize( Result );

		return Result;
	}

	void Free( void* Memory ) 
	{
		VirtualFree( Memory, 0, MEM_RELEASE );
	}

	size_t GetSize( void* Memory )
	{
		MEMORY_BASIC_INFORMATION PageInfo;
		VirtualQuery( Memory, &PageInfo, sizeof(PageInfo) );

		return PageInfo.RegionSize;
	}

	bool Resize( void* Memory, size_t& NewSize )
	{
		// Resizing is not supported by VirtualAlloc
		return false;
	}

protected:
	// The handle to the heap
	HANDLE hHeap;
};

}